#ifndef XXTHREAD_H
#define XXTHREAD_H

#include <QThread>
#include <functional>
#include <QSharedPointer>
#include <QMap>
#include <QMutex>

#include <QSemaphore>

class XXthreadTask{
public:
    XXthreadTask(){block=nullptr;}
    XXthreadTask(const XXthreadTask &action){*this=action;}
    void operator=(const XXthreadTask &action){
        name = action.name;
        block = action.block;
        mainThread = action.mainThread;
    }
    bool mainThread;
    std::function<void(void)> block;
    QString name;
};

class XXthread : public QThread
{
    Q_OBJECT
public:
    XXthread(QObject *parent = nullptr);
    virtual ~XXthread();

    /**
     * @brief addTask 添加一个任务，如果是非单步模式，主线程任务可能与非主线程任务同时执行，
     * 亦有可能本线程结束后，主线程任务仍未完成，所以不建议在非单步模式下添加主线程任务。
     * @param block 具体任务。
     * @param mainThread 是否运行在主线程，默认是否。
     * @param name 任务名称，用于内部标识，暂未开放。
     */
    void addTask(std::function<void(void)> block, bool mainThread = false, QString name = "");

    /**
     * @brief setFinish 设置运行结束后的回调，当任务列表为空时，本线程就会停止，并触发此回调。
     * @param block 具体执行。
     */
    void setFinish(std::function<void(void)> block);

    /**
     * @brief setStepMode 设置为单步模式，最好在start之前设置，需要与 nextStep 配合使用。
     * @param enable
     */
    void setStepMode(bool enable);

    /**
     * @brief nextStep 下一步，配合单步模式下使用。
     */
    void nextStep();

    /**
     * @brief setDelay 设置延迟启动。
     * @param ms
     */
    void setDelay(int ms);

    /**
     * @brief start 启动本线程。
     */
    void start();

    /**
     * @brief requestInterruption 请求线程中止，调用后，并不是立即停止线程，需要待线程正在执行的任务完成之后才能停止。
     */
    void requestInterruption();

private:
    // [-] 线程主体运行相关。
    /**
     * @brief run 线程执行主体函数。
     */
    void run();

    /**
     * @brief onFinished 线程执行结束槽函数。
     */
    Q_SLOT void onFinished();
    // [!] 线程主体运行相关。


    // [-] 定时器相关。
    /**
     * @brief startDelayTimer 开启延迟执行定时器
     */
    void startDelayTimer();

    /**
     * @brief killDelayTimer 关闭延迟执行定时器
     */
    void killDelayTimer();

    /**
     * @brief timerEvent 定时器事件，QObject的虚函数。
     * @param event
     */
    void timerEvent(QTimerEvent *event);
    // [!] 定时器相关。


    // [-] 任务列表增删改查相关操作。
    /**
     * @brief addTask 添加任务，与上面的addTask不同之处有，形参和同步锁。
     * @param task 具体任务。
     */
    void addTask(const XXthreadTask &task);

    /**
     * @brief takeFirstTask 取出第一个任务。
     * @return
     */
    XXthreadTask takeFirstTask();

    /**
     * @brief removeAllTask 移除所有任务。
     */
    void removeAllTask();

    /**
     * @brief taskCount 获取任务数量。
     * @return
     */
    int taskCount();
    // [!] 任务列表增删改查相关操作。


    // [-] 运行在主线程任务的相关操作。
    Q_SIGNAL void sigMainThread(std::function<void(void)> block);
    Q_SLOT void onMainThread(std::function<void(void)> block);
    // [!] 运行在主线程任务的相关操作。

private:
    /* 延迟执行定时器ID */
    int _delayTimerID;

    /* 延迟执行时长 */
    int _delayDuration;

    /* 本线程正常结束回调 */
    std::function<void(void)> _finishBlock;

    /* 是否为单步模式标识 */
    bool _stepMode;

    /* 任务列表 */
    QList<XXthreadTask> _tasks;

    /* 任务列表锁 */
    QMutex _tasksMutex;

    /* 任务列表信号量，配合单步模式使用 */
    QSemaphore *_taskSemaphore;
};


class XXthreadDispatcher : public QObject
{
    Q_OBJECT
public:
    XXthreadDispatcher() {connect(this,&XXthreadDispatcher::sigDeleteLater,this,&XXthreadDispatcher::onDeleteLater,Qt::QueuedConnection);}
    virtual ~XXthreadDispatcher() {}
    static XXthreadDispatcher* instance();

    QSharedPointer<XXthread> create(const QString &name);
    QSharedPointer<XXthread> get(const QString &name);
    void remove(const QString &name);

private:
    Q_SIGNAL void sigDeleteLater(QSharedPointer<XXthread> thread);
    Q_SLOT void onDeleteLater(QSharedPointer<XXthread> thread){Q_UNUSED(thread)}

private:
    static XXthreadDispatcher *_instance;
    QMutex _nameToThreadMutex;
    QMap<QString,QSharedPointer<XXthread>> _nameToThread;
};
#endif
